Wednesday Code and Notes (Week 3)
Table of Contents
1 Promela code
You can download the Promela code here.
2 Notes
So far we've seen two crit sec solutions: - Dekker's algorithm (attempt 5) - Manna-Pnueli algorithm Assumptions: - reads and writes to shared memory are atomic - nothing else is available that can be executed atomically OG (Owicki-Gries) - annotate each location with an invariant - show (separately for each process) that the assertions are inductive - show interference freedom (common ⊕ tp ⊕ tq) = 1 ∧ P@p4 ⇒ tp = 1 ∧ Q@q4 ⇒ tq = 1 ∧ ¬(common=tp ∧ common=tq) If P@p4=⊤ Q@q4=⊤, then (common ⊕ tp ⊕ tq) = 1 ∧ // an odd number of bits are set tp = 1 ∧ // at least two of them are set tq = 1 ∧ // hence: all three are set ¬(common=tp ∧ common=tq) // but: all three are different Is this invariant preserved by the transition from q3 to q4? We need to prove the following impl: (common ⊕ tp ⊕ tq) = 1 ∧ P@p4 ⇒ tp = 1 ∧ ⊥ ⇒ tq = 1 ∧ ¬(common=tp ∧ common=tq) ∧ tq = 1 ⇒ (common ⊕ tp ⊕ tq) = 1 ∧ // this is already in our assumptions P@p4 ⇒ tp = 1 ∧ // this is already in our assumptions ⊤ ⇒ tq = 1 ∧ // tq = 1 is already in our assumption ¬(common=tp ∧ common=tq) ∧ // this is already in our assumptions Desiderata: - Mutual exclusion - Eventual entry - Deadlock freedom - Absence of unnecessary delay Eventual entry: □(P@waitp ⇒ ◇P@csp) Linear waiting: is a linear time property (more on this later) Bounded waiting is not. If you look at a single behaviour, you can tell how many bypasses happened in that behaviour. But you don't know if there's another behaviour with more bypasses or not. What would the annotation in the CS be? p1: non-crit p2: wantp := true p3: last := 1 p4: await wantq=false ∨ last ≠ 1 { wantp = true ∧ (wantq=false ∨ last ≠ 1) } p5: critical section p6: wantp = false Can q interfer with this annotation? q1 -> q2: nothing happens, so no q2 -> q3: we might have interfence q3 -> q4: setting last := 2 cannot falsify last ≠ 1 q4 -> q5: before this transition, wantp=false or last≠2 last ≠ 2 is the only that doesn't contradict p4's annotation, but if so, the second conjunct of the annotation cannot hold. Our annotation can be interfered with only by q2->q3. We compensate by { wantp = true ∧ (wantq=false ∨ last ≠ 1 ∨ Q@q3) } In Peterson's algorithm: - the in[i] flag is: which trap is process i currently at - the last[i] flag is: the PID of the last process to approach the i:th trap Does Peterson's algorithm obey the LCR restriction? The problematic line is the await - k, j and i: not shared - in[k] and last[j] are in fact shared - hence this presentation does not satisfy LCR restr. - but: we can read first in[k] then last[j] without breaking the algorithm np,nq are both currently 0 process p reads 0 from nq process q reads 0 from np process p writes 0+1 to np process q writes 0+1 to nq If we assume p2 is executed atomically, the tiebreaker is pointless. p picks ticket number 1 q picks ticket number 2 p enters CS, finishes, sets np=0 p picks ticket number 3 q enters CS, finishes, sets nq=0 q picks ticket number 4 ... hence: ticket numbers can grow unboundedly large - it's theoretically possibly that we run out of space in the integer variables. in practice, will never happen. - we can't meaningfully analyse this algorithm with Spin, because the required state space is infinite. Idea: Invariant (1) can be proven inductive if we annotate every location with (1). Once we have that, we know that □(np = 0 ⇔ P@p1..2) Once we have proven invariant (1), because we know that it holds in every state, we get to assume it in the proof of future invariants. Q: in Simplified Bakery, is "for all" universal quantification (∀) or is it a for-loop? A: the latter P@p1..2 is shorthand for P@p1 ∨ P@p2 Q: could we leave out disjunct #1 on the await on p4. A: No, we can't. If we do, then if a process stays in the non-critical section forever, then we're never getting past the await. Hence: we lose eventual entry. Q: what happens if we drop the post-protocol? We skip the number[i] = 0 at p6. A: the procs will get one turn exactly, period, if the first process to exit the crit sect never tries to reenter. Let's split line p2,q2 into two! 1. p reads nq = 0 2. q reads np = 0 3. q sets nq = 1 4. q gets to enter the CS 5. p sets np = 1 6. p gets to enter the CS, because np ≤ nq, 1 ≤ 1 If we just split p2 into read-then-write, we break mutual exclusion.